<?php

namespace App\Http\Controllers;

use App\Models\Project;
use App\Models\Schedule;
use App\Models\Inspection;
use Illuminate\Http\Request;
use App\Models\Inspection\Node;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause;
use Maatwebsite\Excel\Writers\CellWriter;
use App\Repositories\InspectionRepository;
use Maatwebsite\Excel\Writers\LaravelExcelWriter;
use Maatwebsite\Excel\Classes\LaravelExcelWorksheet;
use App\Http\Requests\Logic\Inspection\StoreResource;
use App\Models\Statistical\StaffDimensionalityInspectionReports;
use App\Models\Statistical\CircleDimensionalityInspectionReports;
use App\Models\Statistical\ProjectDimensionalityInspectionReports;

/**
 * 巡检业务逻辑控制器
 *
 * Date: 25/04/2018
 * @author George
 * @package App\Http\Controllers
 */
class InspectionController extends Controller
{
	protected $inspectionRepository;

	/**
	 * InspectionController constructor.
	 * @param InspectionRepository $inspectionRepository
	 */
	public function __construct(InspectionRepository $inspectionRepository)
	{
		$this->inspectionRepository = $inspectionRepository;
	}

	/**
	 * Date: 01/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
	 */
    public function index(Request $request)
    {
    	$user = Auth::user();
    	$start = $request->get('start');
    	$end = $request->get('end');
    	$query = Project::query();
    	return $query->with('lines.circles.nodes')->where('company_id', $user->company_id)->get();
    }

	/**
	 * 创建巡检记录
	 *
	 * Date: 27/04/2018
	 * @author George
	 * @param StoreResource $request
	 * @return \Illuminate\Http\JsonResponse
	 * @throws \App\Exceptions\GeneralException
	 */
    public function store(StoreResource $request)
    {
    	$attributes = $this->extractInputFromRules($request, $request->rules());
    	array_pull($attributes, 'images');
    	$node = Node::with('circle.line')->where('id', $attributes['node_id'])->first();

    	if (! $node) {
    		return failed('巡检节点不存在');
		}

		if (! $node->circle) {
    		return failed('巡检节点未关联到圈');
		}

		if (! $node->circle->line) {
    		return failed('巡检节点未关联到线路');
		}

		$inspection = $this->inspectionRepository->store($attributes, $request->file('images'));

    	return stored($inspection);
	}

	/**
	 * 获取巡检节点详情
	 *
	 * Date: 25/04/2018
	 * @author George
	 * @param Inspection $inspection
	 * @return \Illuminate\Http\JsonResponse
	 */
    public function show(Inspection $inspection)
    {
    	$inspection->images = $inspection->images()->get();
    	return success($inspection);
    }

	/**
	 * Date: 07/05/2018
	 * @author George
	 * @param Request $request
	 * @param Inspection $inspection
	 */
    public function update(Request $request, Inspection $inspection)
    {
        // todo
    }

	/**
	 * Date: 07/05/2018
	 * @author George
	 * @param Inspection $inspection
	 */
    public function destroy(Inspection $inspection)
    {
        // todo
    }

	/**
	 * 指派巡检任务
	 *
	 * Date: 06/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 * @throws \Throwable
	 */
	public function assign(Request $request)
	{
		$this->validate($request, [
			'schedule_id' => 'required',
			'line_id' => 'required|integer',
		]);

		$line_id = $request->get('line_id');
		$schedule_id = $request->get('schedule_id');

		$schedule = Schedule::findOrFail($schedule_id);
		$schedule->line_id = $line_id;
		$schedule->saveOrFail();
		return stored($schedule);
    }

	/**
	 * 项目维度巡检报表
	 *
	 * Date: 09/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function projectDimensionalityReports(Request $request)
	{
		$start = $request->get('start');
		$end = $request->get('end');
		$export = $request->get('export');
		$project_name = $request->get('project_name');
		$project_id = $request->get('project_id');
		$paginate = $request->get('paginate', 15);

		$query = ProjectDimensionalityInspectionReports::query()->where('company_id', Auth::user()->company_id);

		if ($start && $end) {
			$query->whereBetween('date', [$start, $end]);
		}

		if ($project_name) {
			$query->where('project_name', 'like', "%{$project_name}%");
		}

		if ($project_id) {
			$query->where('project_id', $project_id);
		}

		/**
		 * 导出数据
		 */
		if ($export) {
			Excel::create('users', function ($excel) use ($query) {
				/**
				 * @var LaravelExcelWriter $excel
				 */
				$excel->sheet('项目列表', function($sheet) use ($query) {
					/**
					 * 设置列宽度
					 * @var LaravelExcelWorksheet $sheet
					 */
					$sheet->setWidth(array(
						'A'     =>  25,
						'B'     =>  10,
						'C'     =>  20,
						'D'     =>  20,
						'E'     =>  10,
						'F'     =>  10,
						'G'     =>  10,
						'H'     =>  10,
						'I'     =>  20,
					));

					/**
					 * 设置对其方式
					 */
					$sheet->cells('A:I', function($cells) {
						/**
						 * @var CellWriter $cells
						 */
						$cells->setAlignment('center');
					});

					$sheet->fromArray($query->get()->map(function ($item) {
						return [
							'项目名称'=> $item->project_name,
							'线路数量' => $item->lines_count,
							'点数完成数量' => $item->nodes_insepcted,
							'点数完成率' => $item->nodes_rate,
							'准点率' => $item->nodes_punctuality,
							'漏点数量' => $item->nodes_uninspected,
							'异常点位' => $item->nodes_errors,
							'异常点位率' => round( $item->nodes_errors / $item->nodes_count) * 100,
							'日期' => $item->date,
						];
					}));
				});
			})->download('xlsx');
		}

		return success($query->paginate($paginate));
	}

	/**
	 * 人员维度巡检报表
	 *
	 * Date: 07/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function staffDimensionalityReports(Request $request)
	{
		$start = $request->get('start');
		$end = $request->get('end');
		$user_name = $request->get('user_name');
		$project_id = $request->get('project_id');
		$paginate = $request->get('paginate', 15);

		$query = StaffDimensionalityInspectionReports::query()
			->where('company_id', Auth::user()->company_id)
			->where('project_id', $project_id);

		if ($start && $end) {
			$query->whereBetween('date', [$start, $end]);
		}

		if ($user_name) {
			$query->where('user_name', 'like', "%{$user_name}%");
		}

		return success($query->paginate($paginate));
    }

	/**
	 * 圈纬度巡检数据报表
	 *
	 * Date: 09/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function circleDimensionalityReports(Request $request)
	{
		$this->validate($request, [
			'date' => 'required',
			'user_id' => 'required',
			'project_id' => 'required',
		]);

		$status = $request->get('status');
		$date = $request->get('date');
		$user_id = $request->get('user_id');
		$project_id = $request->get('project_id');
		$paginate = $request->get('paginate', 15);

		$query = DB::table('circle_node_pivot')->select([
			'inspections.id as inspection_id',
			'circles.name as cirlce_name',
			'circles.id as cirlce_id',
			'nodes.name as node_name',
			'circle_node_pivot.time',
			'inspections.status',
			'inspections.location'
		])
			->join('circles', 'circle_node_pivot.circle_id', '=', 'circles.id')
			->join('nodes', 'circle_node_pivot.node_id', '=', 'nodes.id');
		if ($status == 1 || ! $status) {
			$query->join('inspections', function ($join) use ($date, $user_id, $project_id, $status) {
				/**
				 * @var JoinClause $join
				 */
				$join->on('circle_node_pivot.node_id', '=', 'inspections.node_id')
					->where('inspections.user_id', $user_id)
					->where('inspections.project_id', $project_id)
					->whereDate('inspections.created_at', $date);
				if ($status != null) {
					$join->where('inspections.status', $status);
				}
			});
		}

		/**
		 * 判断巡检记录
		 */
		if ($status == 2) {
			$query->leftJoin('inspections', function ($join) use ($date, $user_id, $project_id, $status) {
				/**
				 * @var JoinClause $join
				 */
				$join->on('circle_node_pivot.node_id', '=', 'inspections.node_id')
					->where('inspections.user_id', $user_id)
					->where('inspections.project_id', $project_id)
					->whereDate('inspections.created_at', $date)
					->whereNull('inspections.status');
			});
		}

		$query->orderBy('circles.id');

		return success($query->paginate($paginate));
    }

	/**
	 * 获取巡检任务详情信息
	 *
	 * Date: 2018/5/22
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function assignmentDetails(Request $request)
	{
		$user = Auth::user();
		$date = $request->get('date');
		$schedule = $user->getSchedule('checkin', $date);

		if (!$schedule || $schedule->line_id === 0) {
			return success([]);
		}

		$assignment = $schedule->line()->select(['id', 'name'])->with('circles')->first();

		$assignment->circles->map(function ($circle) use ($schedule) {
			/**
			 * @var Inspection\Circle $circle
			 */
			$circle->nodes = $circle->nodes()->with(['inspection' => function ($inspectionsQuery) use ($schedule, $circle) {
				/**
				 * @var Builder $inspectionsQuery
				 */
				$inspectionsQuery->select(['id', 'schedule_id', 'line_id', 'circle_id', 'node_id', 'user_id', 'user_name', 'location', 'created_at']);
				$inspectionsQuery->where('circle_id', $circle->id)->whereBetween('created_at', [$schedule->start_timestamp, $schedule->end_timestamp]);
				$inspectionsQuery->with('images');
			}, 'images'])->get();
			return $circle;
		});

		return success($assignment);
	}

	/**
	 * 获取巡检任务
	 *
	 * Date: 06/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function assignment(Request $request)
	{
		$user = Auth::user();
		$date = $request->get('date');
		$schedule = $user->getSchedule('checkin', $date);

		if (!$schedule || $schedule->line_id === 0) {
			return success([]);
		}

		$summary['circle_rate'] = 0;
		$summary['circle_finished'] = 0;
		$summary['node_rate'] = 0;
		$summary['node_finished'] = 0;
		$summary['node_error'] = 0;
		$summary['node_punctuality'] = 0;

		$line = $schedule->line()->withCount('circles')->withCount('nodes')->first();
		if ($line) {
			$summary['circles_count'] = $line->circles_count;
			$summary['nodes_count'] = $line->nodes_count;
			$circles = $line->circles()->get();
			if ($circles) {
				foreach ($circles as $circle) {
					/**
					 * @var Inspection\Circle $circle
					 */
					$nodes = $circle->nodes()->where('line_id', $line->id)->get();
					if ($nodes) {
						$node_finished = 0;
						foreach ($nodes as $node) {
							/**
							 * @var Node $node
							 */
							$inspection = $inspection = Inspection::query()
								->where('line_id', $line->id)
								->where('circle_id', $circle->id)
								->where('node_id', $node->id)
								->whereBetween('created_at', [$schedule->start_timestamp, $schedule->end_timestamp])
								->first();
							if ($inspection) {
								$node_finished += 1;
								$summary['node_finished'] += 1;
								$summary['node_rate'] = round($summary['node_finished'] / $summary['nodes_count'], 2) * 100;
								if (!$inspection->status) {
									$summary['node_error'] += 1;
								}
							}
						}
						$summary['circles'][] = [
							'id' => $circle->id,
							'nodes_count' => $nodes->count(),
							'node_finished' => $node_finished
						];
					}
				}
			}
		}

		if ($summary['node_finished'] > 0) {
			$summary['node_punctuality'] = round($summary['node_error'] / $summary['node_finished']) * 100;
		}

		return success($summary);
    }

	/**
	 * 获取圈维度巡检明细
	 *
	 * Date: 17/05/2018
	 * @author George
	 * @param Request $request
	 * @return \Illuminate\Http\JsonResponse
	 */
	public function circleDetails(Request $request)
	{
		$this->validate($request, [
			'circle_id' => 'required',
			'date' => 'required',
		]);

		$circle_id = $request->get('circle_id');
		$date = $request->get('date');

		$nodes_count = DB::table('circle_node_pivot')->where('circle_id', $circle_id)->count();

		$query = Inspection::query()->select([
			'id', 'user_id', 'user_name', 'node_name', 'created_at', 'status', 'location', 'longitude', 'latitude'
		])->with(['images', 'user' => function ($query) {
			/**
			 * @var Builder $query
			 */
			$query->select(['id', 'name', 'avatar']);
		}]);

		$inspections = $query->where('circle_id', $circle_id)->whereDate('created_at', $date)->get();

		$nodes_errors = $inspections->where('status', 0)->count();
		$nodes_inspected = $inspections->where('status', 1)->count();

		return success([
			'nodes_count' => $nodes_count,
			'nodes_errors' => $nodes_errors,
			'nodes_uninspected' => $nodes_count - $inspections->count(),
			'nodes_inspected' => $nodes_inspected,
			'inspections' => $inspections,
		]);
    }
}
